#include "Preprocessor.hpp"

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_void, 0, 0, 1)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_resize, 0, 0, 2)
	ZEND_ARG_INFO(0, start)
	ZEND_ARG_INFO(0, size)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setHomeUrl, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setRedirectUrl, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setSmileysUrl, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setSessionId, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setUserUrl, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setFlags, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_preprocessor_setText, 0, 0, 1)
	ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

static zend_function_entry preprocessor_methods[] = {
	PHP_ME(Preprocessor, __construct,    arginfo_preprocessor_void,           ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
	PHP_ME(Preprocessor, analize,        arginfo_preprocessor_void,           ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, resize,         arginfo_preprocessor_resize,         ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, prepare,        arginfo_preprocessor_void,           ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, free,           arginfo_preprocessor_void,           ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setHomeUrl,     arginfo_preprocessor_setHomeUrl,     ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setRedirectUrl, arginfo_preprocessor_setRedirectUrl, ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setSmileysUrl,  arginfo_preprocessor_setSmileysUrl,  ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setUserUrl,     arginfo_preprocessor_setUserUrl,     ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setSessionId,   arginfo_preprocessor_setSessionId,   ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, getText,        arginfo_preprocessor_void,           ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setText,        arginfo_preprocessor_setText,        ZEND_ACC_PUBLIC)
	PHP_ME(Preprocessor, setFlags,       arginfo_preprocessor_setFlags,       ZEND_ACC_PUBLIC)
	{NULL, NULL, NULL}
}; 

void preprocessor_free_storage(void *object TSRMLS_DC) {
	preprocessor_object *obj = (preprocessor_object *)object; 
	if (obj -> tp) {
		delete obj -> tp; 
		obj -> tp = 0; 
	}
	zend_hash_destroy(obj -> std.properties); 
	FREE_HASHTABLE(obj -> std.properties); 
	efree(obj); 
}

zend_object_value preprocessor_create_handler(zend_class_entry *type TSRMLS_DC) {
	zend_object_value retval; 
	
	preprocessor_object *obj = (preprocessor_object *)emalloc(sizeof(preprocessor_object)); 
	memset(obj, 0, sizeof(preprocessor_object)); 
	obj -> std.ce = type; 
	
	ALLOC_HASHTABLE(obj -> std.properties); 
	zend_hash_init(obj -> std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); 
	object_properties_init(&(obj -> std), preprocessor_ce); 
	retval.handle   = zend_objects_store_put(obj, NULL, preprocessor_free_storage, NULL TSRMLS_CC); 
	retval.handlers = &preprocessor_object_handlers; 
	return retval; 
}

void init_text_preprocessor() {
	zend_class_entry ce; 
	
	// Evilworlds.Text.Preprocessor
	INIT_CLASS_ENTRY(ce, PREPROCESSOR_CLASS_NAME, preprocessor_methods); 
	preprocessor_ce = zend_register_internal_class(&ce TSRMLS_CC); 
	preprocessor_ce -> create_object = preprocessor_create_handler;
	memcpy(&preprocessor_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 
	preprocessor_object_handlers.clone_obj = NULL; 
	preprocessor_ce -> ce_flags |= ZEND_ACC_FINAL_CLASS; 
	
	zend_declare_class_constant_long(preprocessor_ce, const_str_length("FLAGS_NONE"),         TP_FLAGS_NONE); 
	zend_declare_class_constant_long(preprocessor_ce, const_str_length("FLAGS_NO_BGCOLOR"),   TP_FLAGS_NO_BGCOLOR); 
	zend_declare_class_constant_long(preprocessor_ce, const_str_length("FLAGS_NO_EXT_LINKS"), TP_FLAGS_NO_EXT_LINKS); 
	zend_declare_class_constant_long(preprocessor_ce, const_str_length("FLAGS_NO_SMILEYS"),   TP_FLAGS_NO_SMILEYS); 
}

void destroy_text_preprocessor() {
	// thing todo...
}

PHP_METHOD(Preprocessor, __construct) {
	zval *object = getThis(), *site_config = NULL, *modules = NULL, **mod_data = NULL; 
	zval *ret, **base_url_string, **smileys_url_string; 
	Url redirect_url, user_url, base_url; 
	
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp = new TextPreprocessor(); 
	
	// Получение конфига common.site
	site_config = evilworlds_get_config("common", "site", NULL); 
	null_if_fail(site_config); 
	null_if_fail(Z_TYPE_P(site_config) == IS_ARRAY); 
	
	// Получаем base_url
	base_url_string = get_array_value(Z_ARRVAL_P(site_config), const_obj_size("base_url"), IS_STRING); 
	null_if_fail(base_url_string); 
	
	// Получаем smileys_url
	smileys_url_string = get_array_value(Z_ARRVAL_P(site_config), const_obj_size("smileys_url"), IS_STRING); 
	null_if_fail(smileys_url_string); 
	
	// Парсим base_url
	base_url.parse(Z_STRVAL_PP(base_url_string), Z_STRLEN_PP(base_url_string)); 
	
	// Задаём smileys_url
	obj -> tp -> setSmileysUrl(Z_STRVAL_PP(smileys_url_string), Z_STRLEN_PP(smileys_url_string)); 
	
	// Получение конфига modules
	modules = evilworlds_get_config("modules", NULL, NULL); 
	null_if_fail(modules); 
	null_if_fail(Z_TYPE_P(modules) == IS_ARRAY); 
	
	zval **url_prefix; 
	
	// Ищем модуль User
	mod_data = get_array_value(Z_ARRVAL_P(modules), const_obj_size("User"), IS_ARRAY); 
	null_if_fail(mod_data); 
	
	// Ищем url_prefix модуля User
	url_prefix = get_array_value(Z_ARRVAL_PP(mod_data), const_obj_size("url_prefix"), IS_STRING); 
	null_if_fail(url_prefix); 
	
	user_url.copy(base_url); 
	user_url.setPath("/", 1); 
	if (Z_STRLEN_PP(url_prefix)) {
		user_url.appendPath(Z_STRVAL_PP(url_prefix), Z_STRLEN_PP(url_prefix)); 
		user_url.appendPath("/", 1); 
	}
	
	// Ищем модуль MainPage
	mod_data = get_array_value(Z_ARRVAL_P(modules), const_obj_size("MainPage"), IS_ARRAY); 
	null_if_fail(mod_data); 
	
	// Ищем url_prefix модуля MainPage
	url_prefix = get_array_value(Z_ARRVAL_PP(mod_data), const_obj_size("url_prefix"), IS_STRING); 
	null_if_fail(url_prefix); 
	
	redirect_url.copy(base_url); 
	redirect_url.setPath("/", 1); 
	if (Z_STRLEN_PP(url_prefix)) {
		redirect_url.appendPath(Z_STRVAL_PP(url_prefix), Z_STRLEN_PP(url_prefix)); 
		redirect_url.appendPath("/", 1); 
	}
	
	obj -> tp -> setUserUrl(user_url); 
	obj -> tp -> setHomeUrl(base_url); 
	obj -> tp -> setRedirectUrl(redirect_url); 
	
	zval *session_cookies = evilworlds_registry_get("session_cookies"); 
	if (!session_cookies || Z_TYPE_P(session_cookies) != IS_BOOL || !Z_BVAL_P(session_cookies)) {
		zval *tmp; 
		zval *session = evilworlds_registry_get("current_sess"); 
		if (session && Z_TYPE_P(session) == IS_OBJECT) {
			MAKE_STD_ZVAL(ret); 
			MAKE_STD_ZVAL(tmp); 
			ZVAL_STRING(tmp, "sid", 1); 
			if (call_function("get", &session, ret, 1, tmp))
				obj -> tp -> setSessionId(Z_STRVAL_P(ret), Z_STRLEN_P(ret)); 
			FREE_ZVAL(tmp); 
			FREE_ZVAL(ret); 
		}
	}
}

PHP_METHOD(Preprocessor, analize) {
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> analize(); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, resize) {
	size_t start = 0, size = 0; 
	bool pointers = false; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llb", &start, &size, &pointers) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> resize(start, size); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, free) {
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> free(); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, prepare) {
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> prepare(); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setFlags) {
	long flags; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> setFlags(flags); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setText) {
	zend_bool enable_html_escape = false, double_encode = true; 
	long html_escape_flags = ENT_COMPAT | ENT_QUOTES; 
	char *charset = NULL, *text, *new_text; 
	int charset_len = 0, text_len;
	size_t new_text_len; 
	
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bls!b", &text, &text_len, &enable_html_escape, &html_escape_flags, &charset, &charset_len, &double_encode) != SUCCESS)
		WRONG_PARAM_COUNT; 
	
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	
	if (enable_html_escape) {
		new_text = php_escape_html_entities_ex((unsigned char *)text, text_len, &new_text_len, false, (int) html_escape_flags, charset, double_encode TSRMLS_CC); 
		if (new_text) {
			obj -> tp -> setText(new_text, new_text_len); 
			efree(new_text); 
		}
	} else
		obj -> tp -> setText(text, text_len); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setSessionId) {
	char *sid; int sid_len = 0; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &sid, &sid_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> setSessionId(sid, sid_len); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setHomeUrl) {
	char *url; int url_len = 0; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url, &url_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> setHomeUrl(url, url_len); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setRedirectUrl) {
	char *url; int url_len = 0; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url, &url_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> setRedirectUrl(url, url_len); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setUserUrl) {
	char *url; int url_len = 0; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url, &url_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> setUserUrl(url, url_len); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, setSmileysUrl) {
	char *url; int url_len = 0; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url, &url_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	obj -> tp -> setSmileysUrl(url, url_len); 
	RETURN_ZVAL(object, true, false); 
}

PHP_METHOD(Preprocessor, getText) {
	zval *object = getThis(); 
	preprocessor_object *obj = (preprocessor_object *)zend_object_store_get_object(object TSRMLS_CC); 
	if (!obj -> tp -> getLength()) {
		RETURN_EMPTY_STRING(); 
	} else {
		RETURN_STRINGL(obj -> tp -> getText(), obj -> tp -> getLength(), 1); 
	}
}
